import java.awt.Dimension;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.util.Arrays;
import java.util.Iterator;

public class ImageProcessor 
{
	private BufferedImage image;
	private BufferedImage resultImage;
	private BufferedImage resultImage2;
	private BufferedImage finishImage;	
	private BufferedImage markedImageResult;
	private BufferedImage enhencedImageResult;
	private Pixel[][] pixels;
	private Pixel[][] result;
	private boolean[][] binaryImage;
	private int[] rawPixels;
	private final int minSegmentSize = 70;
	private int imageWidth;
	private int imageHeight;
	
	public BufferedImage getImage() 
	{
		return image;
	}
	
	public BufferedImage getFinishImage() {
		return finishImage;
	}
	
	public void setImage(BufferedImage image) 
	{
		this.image = image;
	}
	
	public BufferedImage getEnhencedImageResult() {
		return enhencedImageResult;
	}

	public void setEnhencedImageResult(BufferedImage enhencedImageResult) {
		this.enhencedImageResult = enhencedImageResult;
	}

	public BufferedImage getMarkedImageResult() 
	{
		return markedImageResult;
	}
	
	public BufferedImage getResultImage() 
	{
		return resultImage;
	}
	
	public BufferedImage getResultImage2() 
	{
		return resultImage2;
	}

	public void setResultImage(BufferedImage resultImage) {
		this.resultImage = resultImage;
	}

	public Dimension getImageSize() 
	{
        return new Dimension(image.getWidth(), image.getHeight());
    }

	public ImageProcessor(BufferedImage pImage) 
	{
        image = pImage;
        
        imageWidth = image.getWidth();
        imageHeight = image.getHeight();
    }
	
	public void doRecognition()
	{
		Log.d("ImageProcessor", "Starting processing image!");
		
		if (rawPixels == null || pixels == null || result == null) 
            if (!convertToPixelMatrix()) 
                return;
		
		Pixel[][] enhencedImage = doMedianFilter(pixels,imageWidth, imageHeight);
		enhencedImageResult = createResultImage(enhencedImage);
		binaryImage = doBinarization(enhencedImage,172);
		resultImage = createResultImage(binaryImage);
		SegmentList sList = new SegmentList(binaryImage, imageWidth, imageHeight);
		sList.doSegmentation();
		sList.removeSmallSegments(minSegmentSize);
		/*updating binaryImage*/
		binaryImage = sList.getBinaryImage();
		resultImage2 = createResultImage(binaryImage);
		MomentProcessor mp = new MomentProcessor(sList.getSegmentList(),binaryImage,imageWidth, imageHeight);
		mp.doMomentProcessing();
		
		for(int i =0;  i < sList.getSegmentList().size(); i++)
		{
			Segment s = sList.getSegmentList().get(i);
			Log.d("Segment no"+i, s.toString());
		}
			
		Pattern pattern = new Pattern(sList.getSegmentList(),enhencedImage,binaryImage,imageWidth,imageHeight);
		pattern.doRecognizing();
		markedImageResult = createResultImage(pattern.getMarkedImage());
		finishImage = createResultImage(pattern.getOriginalImage());
		Log.d("ImageProcessor", "Ending processing image!");
	}
	
	private boolean convertToPixelMatrix() 
	{
        try 
        {
            rawPixels = grabPixels(image);
            pixels = new Pixel[imageWidth][imageHeight];
            result = new Pixel[imageWidth][imageHeight];
            for (int i = 0; i < imageHeight; ++i) 
                for (int j = 0; j < imageWidth; ++j) 
                    pixels[j][i] = new Pixel(rawPixels[j + i * imageWidth]);
        } 
        catch (Exception e) 
        {
            e.printStackTrace();            
            return false;
        }
        return true;
    }
	
    private int[] grabPixels(BufferedImage source) throws Exception 
    {
        PixelGrabber grabber = new PixelGrabber((Image) source, 0, 0, source.getWidth(), source.getHeight(), false);
        source.flush();
        if (!grabber.grabPixels()) {
            throw new Exception("Unable to grab pixels");
        }
        int[] pixels;
        pixels = (int[]) grabber.getPixels();
        grabber.abortGrabbing();
        grabber = null;
        return pixels;
    }
	
 /*   private Pixel[][] sharpEdges(Pixel[][] image)
    {
    	
    }
  */  
	private boolean[][] doBinarization(Pixel[][] image, int treshold)
	{
		Log.d("ImageProcessor", "Starting binarization!");
		boolean[][] result = new boolean[imageWidth][imageHeight];
		
		for (int y = 0; y < imageHeight; ++y) 
		{
            for (int x = 0; x < imageWidth; ++x) 
            {
                int r = image[x][y].r; 
                int g = image[x][y].g; 
                int b = image[x][y].b;
                
                //double[] hsv = ColorTransforms.rgb2hsv(r, g, b);
                /*?!?!?!*/
                if (r > 125 && g > 125 && b < 110)
                //if (r > 150 && g > 130 && b < 120)                
                    result[x][y] = true;                
                 else 
                    result[x][y] = false;                
            }
        }
		
		Log.d("ImageProcessor", "Ending binarization!");
		return result;
	}
	
	private BufferedImage createResultImage(boolean[][] binaryImage) 
	{
        int[] resultTable = new int[imageWidth * imageHeight];
        for (int i = 0; i < imageHeight; ++i) 
            for (int j = 0; j < imageWidth; ++j) 
                resultTable[j + i * imageWidth] = binaryImage[j][i] == true ? 0xFFFFFFFF : 0xFF000000;
                    
        Image img = Toolkit.getDefaultToolkit().createImage
        	(new MemoryImageSource(imageWidth, imageHeight, resultTable, 0, imageWidth));
       
        return ImageCreator.createImage(img);
    }
	
	private BufferedImage createResultImage(Pixel[][] pixels) 
	{
        int[] resultTable = new int[imageWidth * imageHeight];
        for (int i = 0; i < imageHeight; ++i) 
            for (int j = 0; j < imageWidth; ++j) 
                resultTable[j + i * imageWidth] = pixels[j][i].toInt();                    
        Image img = Toolkit.getDefaultToolkit().createImage
        	(new MemoryImageSource(imageWidth, imageHeight, resultTable, 0, imageWidth));
        return ImageCreator.createImage(img);
    }
	
	private Pixel[][] doMedianFilter(Pixel[][] image, int width, int height)
	{
		Pixel[][] secondImage =  new Pixel[width][height];
		
		/*int pomTableR[] = new int[9];
		int pomTableG[] = new int[9];
		int pomTableB[] = new int[9];
		*/
		int index;
		//int size = 3;
		
		for (int i = 0; i < height; ++i) 
		{
            for (int j = 0; j < width; ++j)
            {
            	if (!(i<2 || i>height-2 || j<2 || j>width-2))
            	{
	            	index = 0;
	            	int pomTableR[] = new int[9];
	        		int pomTableG[] = new int[9];
	        		int pomTableB[] = new int[9];
	        		
	            	for(int m = i-1; m<=i+1;++m)
	            	{
	            		for(int n = j-1; n<=j+1; ++n)
	            		{         
	            			int r = image[n][m].r;
	            			int g = image[n][m].g;
	            			int b = image[n][m].b;
	            			
	            			pomTableR[index] = r;
	            			pomTableG[index] = g;
	            			pomTableB[index] = b;
	            			//System.out.println(index);
	            			index++;
	            		}
	            	}
	            	
	            	Arrays.sort(pomTableR);
	            	//System.out.println(Arrays.toString(pomTableR));
	            	Arrays.sort(pomTableG);
	            	Arrays.sort(pomTableB);
	            	
	            	/*secondImage[j][i].r=pomTableR[4];
	            	secondImage[j][i].g=pomTableG[4];
	            	secondImage[j][i].b=pomTableB[4];
	            	*/
	            	secondImage[j][i] = new Pixel(pomTableR[4],pomTableG[4],pomTableB[4]);
            	}
            	else
            	{
            		secondImage[j][i] = new Pixel(image[j][i].r,image[j][i].g,image[j][i].b);
            	}
            }
		}			
		
		return secondImage;
	}
}
